package cn.wanda.bi.sunshine.platform.server.client.wrapper;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;

import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import cn.wanda.bi.sunshine.platform.server.SunshineCode;
import cn.wanda.bi.sunshine.platform.server.bean.KeyCache;
import cn.wanda.bi.sunshine.platform.server.bean.mapper.AuthMappingMapper;
import cn.wanda.bi.sunshine.platform.server.bean.model.AuthMapping;
import cn.wanda.bi.sunshine.platform.server.bean.model.AuthMappingExample;
import cn.wanda.bi.sunshine.platform.server.client.WechatAuthClient;
import cn.wanda.bi.sunshine.platform.server.utils.JsonUtil;
import cn.wanda.bi.sunshine.platform.server.utils.exception.ClientException;
import cn.wanda.bi.sunshine.platform.server.utils.exception.SunshineException;

/**
 * Created by wangfupeng1
 */
@Component
public class AuthClientWrapper {
	public static final Logger logger = LoggerFactory.getLogger(AuthClientWrapper.class);

	public static final String  CLIENT_CREDENTIAL = "client_credential";
	public static final String  JSAPI = "jsapi";
	public static final String  AUTHORIZATION_CODE = "authorization_code";
	public static final String  LANG = "zh_CN";

	@Autowired
	private WechatAuthClient wechatAuthClient;
	@Autowired
	private AuthMappingMapper authMappingMapper;
	
	@Cacheable(value = "cache:wechat", key = "'cache:wechat:authaccesstoken'+#appid")
	public String getAccessToken(String appid)  {
		String authWechatAppid = appid;
		String authWechatSecret = getSecret(appid);
		String accessTokenString = wechatAuthClient.accessToken(CLIENT_CREDENTIAL, authWechatAppid, authWechatSecret);
		Map<String, String> map = JsonUtil.toObject(accessTokenString, Map.class);
		if (accessTokenString == null || map.get("errcode") != null) {
			logger.info("errcode: " + map.get("errcode"));
			logger.info("errmsg: " + map.get("errmsg"));
			throw new SunshineException(SunshineCode.WECHAT_AUTH_ERROR_GET_ACCESS_TOKEN);
		}
		return map.get("access_token");
	}
	
	public String getSecret(String appid) {
		AuthMappingExample authMappingExample = new AuthMappingExample();
        authMappingExample.createCriteria().andAppidEqualTo(appid);
		List<AuthMapping> authMappings = authMappingMapper.selectByExample(authMappingExample);
		if(CollectionUtils.isEmpty(authMappings))
			throw new SunshineException(SunshineCode.APPID_ERROR_NOT_FOUND_IN_DATABASE);
		return authMappings.get(0).getSecret();
	}

	public String getJsApiTicket(String accessToken) {
		String JsApiTicketString = wechatAuthClient.jsapiTicket(accessToken, JSAPI);
		Map<String, Object> map = JsonUtil.toObject(JsApiTicketString, Map.class);

		if (JsApiTicketString == null || map.get("ticket")==null) {
			throw new SunshineException(SunshineCode.WECHAT_AUTH_ERROR_GET_JSAPI);
		}
		if((Integer)map.get("errcode")!=0)
			throw new ClientException((Integer)map.get("errcode"),(String)map.get("errmsg"));
		return (String)map.get("ticket");
	}

	private String byteToStr(byte[] byteArray) {
		String strDigest = "";
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
		for (int i = 0, length = byteArray.length ; i < length; i++) {
			byte mByte = byteArray[i];
			char[] tempArr = new char[2];
			tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
			tempArr[1] = Digit[mByte & 0X0F];
			String s = new String(tempArr);
			strDigest += s;
		}
		return strDigest;
	}

	public String getSignature(String ticket, String nonceStr, String timeStamp, String url)  {
		String sKey = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
		logger.info("sKey:"+sKey);
		String ciphertext = null;
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		byte[] digest = md.digest(sKey.toString().getBytes());
		ciphertext = byteToStr(digest);
		return ciphertext.toLowerCase();
	}
	
	@Cacheable(value = "cache:wechat", key = "'cache:wechat:openid:appid:'+#appid+':code:'+#code")
	public Map<String, String> getOpenId(String appid, String code){
		String authWechatAppid = appid;
		String authWechatSecret = getSecret(appid);
		String openIdString = wechatAuthClient.openId(authWechatAppid, authWechatSecret, code, AUTHORIZATION_CODE);
		Map<String, String> map = JsonUtil.toObject(openIdString, Map.class);
		if(map.get("errcode")!=null)
			throw new SunshineException(SunshineCode.WECHAT_MINI_APP_ERROR_GET_OPEN_ID);
		return map;
	}

	public Map<String, String> getUserInfo(String openId,String accessToken){
		String unionIdString = wechatAuthClient.userInfo(accessToken, openId, LANG);
		Map<String, String> map = JsonUtil.toObject(unionIdString, Map.class);
		if(map.get("errcode")!=null)
			throw new SunshineException(SunshineCode.WECHAT_MINI_APP_ERROR_GET_UNION_ID);
		return map;
	}
	
}
